package com.wmx.wmxredis.properties;

import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * EnvironmentAware 接口由任何希望被通知其运行的{@link Environment}的bean实现。
 * 用于轻松获取服务当前生效的全局application.yml文件的配置内容，而不用在指定配置文件路径。
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2023/9/10 17:47
 */
@Component
public class AppEnvironment implements EnvironmentAware {

    private final List<PropertySource> allPropertySource = new ArrayList<>();

    /**
     * 设置此组件运行的｛@code Environment｝
     * allPropertySource 塞进去的对象通常就是服务当前生效的全局 application.yml 文件资源对象，通常是一个。
     * 如：[OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.yml]'}]
     *
     * @param environment
     */
    @Override
    public void setEnvironment(Environment environment) {
        if (!allPropertySource.isEmpty()) {
            return;
        }
        if (environment instanceof AbstractEnvironment) {
            MutablePropertySources propertySources = ((AbstractEnvironment) environment).getPropertySources();
            for (PropertySource propertySource : propertySources) {
                if (propertySource instanceof OriginTrackedMapPropertySource) {
                    allPropertySource.add(propertySource);
                }
            }
        }
    }

    /**
     * 获取系统当前生效的全局 application.yml 的全部配置，而不用在指定具体的文件路径。
     * 通常服务部署运行时，读取都是jar包外部的配置，所以与位置无关，读取的都是服务当前使用的配置。
     *
     * <pre>
     *   不知道为什么，返回的value如果是Object类型，后台取值一切正常，但是返回给页面时，就会json解析异常而报错：
     *   SyntaxError: JSON.parse: end of data when ',' or ']' was expected at line 1 column 11141 of the JSON data
     *   猜测是和yml中配置了某些特殊内容有关，比如数组，因为当只留少数简单配置时是可以的。
     *   所以为了防止上述问题，value统一转字符串返回。
     * </pre>
     *
     * @return
     */
    public Map<String, String> getAllYmlConfig() {
        Map<String, String> configMap = new TreeMap<>();
        for (PropertySource propertySource : allPropertySource) {
            Object source = propertySource.getSource();
            if (source instanceof Map) {
                for (Map.Entry<String, Object> entry : ((Map<String, Object>) source).entrySet()) {
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    configMap.put(key, value.toString());
                }
            }
        }
        return configMap;
    }

    /**
     * 读取指定 key 的配置。
     *
     * @param ymlKey ：全局 yml 配置的 key 名称。
     * @return
     */
    public String getYmlByKey(String ymlKey) {
        return getAllYmlConfig().get(ymlKey);
    }

}
